# -*- coding: utf-8 -*-
# @Time : 2022/6/1 15:44
# @Author : x30003433
import hashlib
import logging
import os
import sys
import time

from xml.dom.minidom import Document

import paramiko
import requests

LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(filename='/root/sign.log', level=logging.INFO, format=LOG_FORMAT)
# logging.basicConfig(filename='/root/xqx/sign.log', level=logging.INFO, format=LOG_FORMAT)

VER_CFG_NAME = "vercfg.xml"
CRL_DATA = "crldata.crl"
VER_CFG_CMS = "vercfg.xml.cms"

PATH = ''
XML_VENDOR = ''
XML_TYPE = ''
XML_VERSION = ''
USER = ''


def remove_old_sign():
    logging.info("remove_old_sign start")
    try:
        if os.path.exists(os.path.join(PATH, VER_CFG_NAME)):
            os.remove(os.path.join(PATH, VER_CFG_NAME))
        if os.path.exists(os.path.join(PATH, CRL_DATA)):
            os.remove(os.path.join(PATH, CRL_DATA))
        if os.path.exists(os.path.join(PATH, VER_CFG_CMS)):
            os.remove(os.path.join(PATH, VER_CFG_CMS))
    except Exception as e1:
        logging.info('remove_old_sign exception:{0}'.format(e1))
        raise RuntimeError("remove_old_sign error")
    logging.info("remove_old_sign success~~~")


# 循环遍历文件下的所有文件并加入到文件列表
def scanner_file(target_path, file_list):
    files = os.listdir(target_path)
    for f in files:
        real_url = os.path.join(target_path, f)
        if os.path.isfile(real_url):
            file_list.append(real_url)
        elif os.path.isdir(real_url):
            scanner_file(real_url, file_list)
        else:
            logging.error("other")


# 创建xml文件
def create_xml(file_path, files_sha_map):
    doc = Document()

    product = doc.createElement("Product")
    doc.appendChild(product)

    vendor = doc.createElement("Vendor")
    txt = doc.createTextNode(XML_VENDOR)
    vendor.appendChild(txt)
    product.appendChild(vendor)

    typ = doc.createElement("Type")
    txt = doc.createTextNode(XML_TYPE)
    typ.appendChild(txt)
    product.appendChild(typ)

    version = doc.createElement("Version")
    txt = doc.createTextNode(XML_VERSION)
    version.appendChild(txt)
    product.appendChild(version)

    for key, value in files_sha_map.items():
        fi = doc.createElement("File")

        k = doc.createElement("FilePath")
        txt = doc.createTextNode(key)
        k.appendChild(txt)
        fi.appendChild(k)

        v = doc.createElement("SHAValue")
        txt = doc.createTextNode(value)
        v.appendChild(txt)
        fi.appendChild(v)

        product.appendChild(fi)
    f = open(file_path, 'w')
    doc.writexml(f, indent='', newl='\n', addindent='\t', encoding='UTF-8')
    f.close()


# 生成vercfg.xml文件
def init_ver_cfg():
    logging.info('init_ver_cfg enter')
    # 1.遍历目标文件下的所有文件
    file_list = []
    scanner_file(PATH, file_list)
    logging.debug("file_list:{0}".format(file_list))
    logging.info("scanner_file success~~~")

    # 2.计算所有文件的sha256值
    sha_map = {}
    for i in file_list:
        with open(i, 'rb') as f:
            sha256obj = hashlib.sha256()
            sha256obj.update(f.read())
            hash_value = sha256obj.hexdigest()
            # key为相对路径的文件名字
            cur_file = i[len(PATH):]
            cur_file = cur_file.replace("\\", '/')
            logging.info("file:{0},sha:{1}".format(cur_file, hash_value))
            sha_map[cur_file] = hash_value
    logging.debug("sha_map:{0}".format(sha_map))
    logging.info("calculate sha256 success~~~")
    # 3.生成xml文件
    create_xml(os.path.join(PATH, VER_CFG_NAME), sha_map)
    logging.info('~~~init_ver_cfg success~~~')


def remove_upload_file(ssh_obj):
    logging.info("remove_upload_file enter")
    # 0.删除服务器上input目录下的所有文件
    try:
        ssh_obj.exec_command("rm -rf /usr1/{0}/input/*".format(USER))
    except Exception as e1:
        logging.info("delete input fail,exception:{0}".format(e1))
        raise RuntimeError("delete input fail")
    logging.info("delete input success~~~")

    # 1. 将生成的xml放在input目录下
    tran = ssh_obj.get_transport()
    sftp = paramiko.SFTPClient.from_transport(tran)
    try:
        sftp.put(os.path.join(PATH, VER_CFG_NAME), "/usr1/{0}/input/{1}".format(USER, VER_CFG_NAME))
    except Exception as e1:
        logging.info("send xml to input fail,exception:{0}".format(e1))
        raise RuntimeError("send xml to input fail")
    sftp.close()
    logging.info("send xml to input success~~~")


def get_other_file(ssh_obj):
    tran = ssh_obj.get_transport()
    sftp = paramiko.SFTPClient.from_transport(tran)
    # 签名需要时间，所以加入等待
    while len(sftp.listdir("/usr1/{0}/input/".format(USER))) < 3:
        logging.info("cur file:{0}".format(sftp.listdir("/usr1/{0}/input/".format(USER))))
        time.sleep(1)

    logging.info("final file:{0}".format(sftp.listdir("/usr1/{0}/input/".format(USER))))
    try:
        sftp.get("/usr1/{0}/input/{1}".format(USER, CRL_DATA), os.path.join(PATH, CRL_DATA))
        logging.info("crldata.crl get success~~~")
        sftp.get("/usr1/{0}/input/{1}".format(USER, VER_CFG_CMS), os.path.join(PATH, VER_CFG_CMS))
        logging.info("vercfg.xml.cms get success~~~")
    except Exception as e1:
        logging.info("get_other_file fail,exception:{0}".format(e1))
        raise RuntimeError("get_other_file fail")
    sftp.close()


# 获取三个签名文件放到输入目录
def get_all_file():
    logging.info("get_all_file enter")
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect("10.29.172.239", 22, "guest", "huawei@123")
    # 0.删除对应服务器input目录下的所有文件
    try:
        remove_upload_file(ssh)
    except RuntimeError as e:
        logging.error(e)
        return False
    # 2.发送post接口
    url = "http://10.29.172.239:8080/jenkins/job/SigService_{0}/build?delay=0sec".format(USER)
    logging.info("url:{0}".format(url))
    res = requests.post(url, data=None)
    logging.info("res.Location :{0};res.status_code:{1}".format(res.headers['Location'], res.status_code))
    if res.status_code != 200 and res.status_code != 201:
        logging.error("send interface fail")
        return False
    logging.info("send interface success~~~")
    # 3. 将文件取回来放在目标路径下
    try:
        get_other_file(ssh)
    except RuntimeError as e1:
        logging.error(e1)
        return False
    ssh.close()
    return True


if __name__ == '__main__':
    logging.info(sys.argv)
    if len(sys.argv) != 5:
        logging.critical("invalid arg count")
        exit(0)
    PATH = sys.argv[1]
    # PATH = '/root/xqx/haha'
    XML_VENDOR = 'HUAWEI'
    XML_TYPE = sys.argv[2]
    XML_VERSION = sys.argv[3]
    USER = sys.argv[4]
    # USER = 'x30003433'

    logging.info("localsign_linux start")
    logging.info(
        "path:{0}, vendor:{1}, type:{2}, version:{3}, user:{4}".format(PATH, XML_VENDOR, XML_TYPE, XML_VERSION,
                                                                       USER))

    try:
        remove_old_sign()
        init_ver_cfg()
        get_all_file()
        print("sign success")
    except RuntimeError as e:
        logging.critical("sign error.exception:{0}".format(e))
        print("sign fail:{0}".format(e))
